import re
import subprocess
import time
import traceback
import typing
from pprint import pprint

import usb.core
import usb.util


def get_usb_lin_dev_list() -> typing.List[dict]:
    r_l = []
    usb_dev_name_map_sn = dict()
    udev_path_map_hid_path = dict()
    id_vender = 0x1993
    id_product = 0x2021
    
    try:
        # 构建 usb_dev_name_map_sn
        devices = usb.core.find(find_all=True, idVendor=id_vender, idProduct=id_product)
        for device in devices:
            usb_dev_name = ""
            serial_number = usb.util.get_string(device, device.iSerialNumber)
            bus_number:str = str(device.bus)
            port_number:str = str(device.port_numbers[0])
            port_numbers:tuple = device.port_numbers
            if (len(port_numbers) == 1):
                # 一般直接连接在电脑上
                usb_dev_name = "/usb{0}/{1}-{2}/{3}-{4}:".format(
                    bus_number, bus_number, port_number, bus_number, port_number)
            elif (len(port_numbers) == 2):
                # 连接在USB hub上
                usb_dev_name = "/usb{0}/{1}-{2}/{3}-{4}.{5}/{6}-{7}.{8}:".format(
                    bus_number, bus_number, port_numbers[0], bus_number, port_numbers[0], port_numbers[1], bus_number, port_numbers[0], port_numbers[1])
            else:
                raise Exception("还不支持构建大于 2 个 port_numbers 的设备")
            usb_dev_name_map_sn[usb_dev_name] = serial_number
        
        # 构建 udev_path_map_hid_path
        res = subprocess.run(["find", "/dev", "-name", "hidraw*"], capture_output=True, text=True, check=True).stdout.strip()
        dev_path_list = res.split("\n")
        for hid_dev in dev_path_list:
            res = subprocess.run(["udevadm", "info", "--name=" + hid_dev], capture_output=True, text=True, check=True).stdout.strip()
            partern = r"P: .*usb.*/.*1993:2021.*" + hid_dev.split("/")[-1]
            matches= re.findall(partern, res)
            assert len(matches) == 1
            res:str = matches[0]
            udev_path = res.replace("P: ", "", 1).strip()
            # print("udev_path:", udev_path)
            udev_path_map_hid_path[udev_path] = hid_dev
        
        # 对比两个 dict 构建映射关系
        for usb_dev_name, serial_number in usb_dev_name_map_sn.items():
            for udev_path, hid_path in udev_path_map_hid_path.items():
                if (usb_dev_name in udev_path):
                    r_l.append({
                        "serial_number": serial_number,
                        "usb_address": usb_dev_name,
                        "dev_path": hid_path
                    })
                    break
        
        # 返回 hwinfo 的输出内容
        return r_l
    except Exception as e:
        # 捕获其他可能的异常
        print("Exception occurred while getting hid device list:\n {0}".format(traceback.format_exc()))
        return r_l
    
    
# def get_usb_lin_device_mapping() -> typing.List[dict]:
#     """
#     1. 使用 usb.core.find 找到 指定 VID 和 PID 的设备，并找到 SN 号
#     2. 获取 USB号和端口号，拼接字符串
#     3. 使用 hwinfo 输出 str
#     4. 在 str 中找到 hiddev 号
#     5. 拼接文件映射路径
#     """
#     # /devices/pci0000:00/0000:00:14.0/usb3/3-5/3-5.2/3-5.2:1.0/usbmisc/hiddev1
#     r_l = []
    
#     # 获得 hwinfo 输出
#     hw_info_str = get_hwinfo_output()
#     if (hw_info_str == None):
#         return r_l
    
#     # 查找 usb 设备
#     devices = usb.core.find(find_all=True, idVendor=0x1993, idProduct=0x2021)
#     for device in devices:
#         serial_number = usb.util.get_string(device, device.iSerialNumber)
#         print("serial_number:", serial_number)
#         bus_number = str(device.bus)
#         port_number = str(device.port_numbers[0])
#         port_numbers = device.port_numbers
#         port_bumber_s = ".".join(str(x) for x in port_numbers)
#         usb_address = "usb" + bus_number + "/" + bus_number + "-" + port_number + "/" +  bus_number + "-" + port_bumber_s + "/" + bus_number + "-" + port_bumber_s
#         usb_address_simple = "usb" + bus_number + "-" + port_bumber_s
#         print("usb_address_simple:", usb_address_simple)
#         partern = r"P:.*" + usb_address + r".*hiddev.*"
#         matches= re.findall(partern, hw_info_str)
#         # print("matches:", matches)
#         if (len(matches) != 1):
#             continue
#         hiddev_path = "/dev/usb/" + matches[0].split("/")[-1]
#         print("hiddev_path:", hiddev_path)
#         print("--------")
#         r_l.append({
#             "serial_number": serial_number,
#             "usb_address": usb_address_simple,
#             "dev_path": hiddev_path
#         })
#     return r_l
    
    
            

        
        
# def main():
#     usb_lin_device = UsbSerialLinDevice()
#     usb_lin_device.start()
#     try:
#         while True:
#             time.sleep(1)
#     except Exception as e:
#         traceback.print_exc()
#     finally:
#         usb_lin_device.stop()
#     # usb_lin_device.stop()
    
    
if __name__ == '__main__':
    res = get_usb_lin_dev_list()
    pprint(res)
    